<?php

namespace app\service;

use app\model\XMLModel;
use SimpleXMLElement;
use think\db\exception\DbException;
use think\facade\Log;

class ParsingXMLService extends BaseService
{
    protected UserService $userService;
    protected GuardService $guardService;
    protected SuperChatService $superChatService;
    protected GiftService $giftService;
    protected BarrageService $barrageService;
    protected RoomService $roomService;
    protected XMLModel $readedXMLModel;
    protected MinioService $minioService;

    protected function initialize() {
        $this->userService = new UserService();
        $this->guardService = new GuardService();
        $this->giftService = new GiftService();
        $this->superChatService = new SuperChatService();
        $this->barrageService = new BarrageService();
        $this->roomService = new RoomService();
        $this->readedXMLModel = new XMLModel();
        $this->minioService = new MinioService();
    }

    /**
     * @param array $fileInfo 文件来源信息
     * @return bool
     */
    public function parsingXML(array $fileInfo): bool
    {
        echo "开始解析 {$fileInfo['file_path']}",PHP_EOL;
        $xml = "http:".$this->minioService->getFileUri($fileInfo["file_path"]);
        $info = simplexml_load_file($xml);
        $userInfo = $content = $scList = $giftList = $guardList = [];
        $roomId = (int)$info->BililiveRecorderRecordInfo->attributes()[0];
        $roomName = (string)$info->BililiveRecorderRecordInfo->attributes()[2];
        if($roomId != $fileInfo["room_id"]) {
            echo "房间ID异常 {$roomId}/{$fileInfo['room_id']}";
            Log::error(date("Y-m-d H:i:s")." 房间ID异常 {$roomId}/{$fileInfo['room_id']}");
            exit();
        }
        $fileInfo["room_id"] = $this->insertRoom([
            "room_id"    => $roomId,
            "room_name"  => $roomName
        ]);
        $this->parsingBarrage($info,$userInfo,$content);
        $this->parsingGift($info,$userInfo,$giftList);
        $this->parsingSc($info,$userInfo,$scList);
        $this->parsingGuard($info,$userInfo,$guardList);
        $this->insertUser($userInfo,$fileInfo["room_id"]);
        unset($userInfo);
        $this->insertBarrage($fileInfo,$content);
        unset($content);
        $this->insertGift($fileInfo,$giftList);
        unset($giftList);
        $this->insertSc($fileInfo,$scList);
        unset($scList);
        $this->insertGuard($fileInfo,$guardList);
        unset($guardList);
        $readed = $this->readedXML($fileInfo);
        if($readed) {
            echo "文件{$fileInfo['file_name']} 成功标为已读";
        }else {
            echo "文件{$fileInfo['file_name']} 未能标为已读";
            Log::error(date("Y-m-d H:i:s")."文件{$fileInfo['file_name']} 未能标为已读");
            exit();
        }
        unset($info);
        return true;
    }

    /**
     * 解析弹幕部分
     * @param SimpleXMLElement $info 读取的xml文件信息
     * @param array $userInfo 弹幕发送者列表
     * @param array $content 弹幕列表
     */
    private function parsingBarrage(SimpleXMLElement &$info, array &$userInfo, array &$content) {
        if(isset($info->d)) {
            $length = count($info->d);
            for($i = 0;$i < $length;$i++) {
                $barrage = json_decode($info->d[$i]->attributes()[2]);
                $id = $barrage[2][0];
                $name = $barrage[2][1];
                $userInfo[$id] = $name;
                $content[$i]["id"] = $id;
                $content[$i]["content"] = $barrage[1];
                echo "用户解析(弹幕)ing ". $i + 1 ."/{$length} ",PHP_EOL;
            }
        }else {
            echo "无弹幕",PHP_EOL;
        }
    }

    /**
     * 解析礼物部分
     * @param SimpleXMLElement $info 读取的xml文件信息
     * @param array $userInfo 礼物赠送者列表
     * @param array $giftList 礼物列表
     */
    private function parsingGift(SimpleXMLElement &$info, array &$userInfo, array &$giftList) {
        if(isset($info->gift)) {
            $length = count($info->gift);
            for($i = 0;$i < $length;$i++) {
                $gift = json_decode($info->gift[$i]->attributes()[4]);
                $id = $gift->uid;
                $name = $gift->uname;
                $userInfo[$id] = $name;
                $giftList[] = [
                    "tid"       => $gift->tid,
                    "gift_id"   => $gift->giftId,
                    "gift_type"   => $gift->giftType,
                    "uuid"   => $gift->uid,
                    "price"     => $gift->price,
                    "gift_name" => $gift->giftName,
                    "gift_count" => $gift->num
                ];
                echo "用户解析(礼物)ing ". $i + 1 ."/{$length} ",PHP_EOL;
            }
        }else {
            echo "无礼物",PHP_EOL;
        }
    }

    /**
     * 解析醒目留言部分
     * @param $info SimpleXMLElement 读取的xml文件信息
     * @param array $userInfo sc发送者列表
     * @param array $scList sc列表
     */
    private function parsingSc(SimpleXMLElement &$info, array &$userInfo, array &$scList) {
        if(isset($info->sc)) {
            $length = count($info->sc);
            for($i = 0;$i < $length;$i++) {
                $sc = json_decode($info->sc[$i]->attributes()[4]);
                $id = $sc->uid;
                $name = $sc->user_info->uname;
                $userInfo[$id] = $name;
                $scList[] = [
                    "tid"           => $sc->id,
                    "gift_id"       => $sc->gift->gift_id,
                    "gift_name"     => $sc->gift->gift_name,
                    "uuid"          => $id,
                    "user_level"    => $sc->user_info->user_level,
                    "price"         => $sc->price,
                    "content"       => $sc->message
                ];
                echo "用户解析(醒目留言)ing ". $i + 1 ."/{$length} ",PHP_EOL;
            }
        }else {
            echo "无醒目留言",PHP_EOL;
        }
    }

    /**
     * 解析大航海部分
     * @param SimpleXMLElement $info 读取的xml文件信息
     * @param array $userInfo 大航海赠送者列表
     * @param array $guardList 大航海列表
     */
    private function parsingGuard(SimpleXMLElement &$info, array &$userInfo, array &$guardList) {
        if(isset($info->guard)) {
            $length = count($info->guard);
            for($i = 0;$i < $length;$i++) {
                $guard = json_decode($info->guard[$i]->attributes()[4]);
                $id = $guard->uid;
                $name = $guard->username;
                $userInfo[$id] = $name;
                $guardList[] = [
                    "uuid"   => $guard->uid,
                    "gift_name" => $guard->gift_name,
                    "gift_id" => $guard->gift_id,
                    "start_time" => $guard->start_time,
                    "price"     => $guard->price,
                ];
                echo "用户解析(大航海)ing ". $i + 1 ."/{$length} ",PHP_EOL;
            }
        }else {
            echo "无大航海",PHP_EOL;
        }
    }

    /**
     * 插入房间 返回房间ID
     * @param array $roomInfo
     * @return mixed
     */
    public function insertRoom(array $roomInfo): mixed
    {
        echo "======= 房间解析 =======",PHP_EOL;
        try {
            $roomId = $this->roomService->insertRoom($roomInfo);
        } catch (DbException $e) {
            Log::error(date("Y-m-d H:i:s")."插入房间异常 ".$e->getMessage());
            exit();
        }
        if(!$roomId) {
            echo "房间解析异常";
        }else {
            echo "房间解析完成，房间号：{$roomId} 下一步，解析用户",PHP_EOL;
        }
        return $roomId;
    }

    /**
     * 插入用户
     * @param array $userInfo User列表
     */
    private function insertUser(array &$userInfo,int $roomId) {
        echo "======= 用户解析 =======",PHP_EOL;
        $userAddResult = $this->userService->userAdd($userInfo,$roomId);
        if(!$userAddResult) {
            echo "用户解析异常";
        }else {
            echo "用户解析完成，下一步，解析弹幕",PHP_EOL;
        }
    }

    /**
     * 插入弹幕
     * @param array $fileInfo 文件来源信息
     * @param array $content 弹幕列表
     */
    private function insertBarrage(array &$fileInfo, array &$content) {
        echo "======= 弹幕解析 =======",PHP_EOL;
        $data = [
            "fileInfo" => $fileInfo,
            "content" => $content
        ];
        $barrageInsertResult = $this->barrageService->insertBarrage($data);
        if(!$barrageInsertResult) {
            echo "弹幕解析异常";
            Log::error(date("Y-m-d H:i:s")."弹幕解析异常");
            exit();
        }else {
            echo "弹幕解析完成，下一步，解析礼物",PHP_EOL;
        }
    }

    /**
     * 插入礼物
     * @param array $fileInfo 文件来源信息
     * @param array $giftList 礼物列表
     */
    private function insertGift(array &$fileInfo, array &$giftList) {
        echo "======= 礼物解析 =======",PHP_EOL;
        $data = [
            "fileInfo" => $fileInfo,
            "giftList" => $giftList
        ];
        $giftInsertResult = $this->giftService->insertGift($data);
        if(!$giftInsertResult) {
            echo "礼物解析异常";
            Log::error(date("Y-m-d H:i:s")."礼物解析异常");
            exit();
        }else {
            echo "礼物解析完成，下一步，解析醒目留言",PHP_EOL;
        }
    }

    /**
     * 插入醒目留言
     * @param array $fileInfo 文件来源信息
     * @param array $scList 醒目留言列表
     */
    private function insertSc(array &$fileInfo, array &$scList) {
        echo "======= 醒目留言解析 =======",PHP_EOL;
        $data = [
            "fileInfo" => $fileInfo,
            "scList" => $scList
        ];
        $scInsertResult = $this->superChatService->insertSC($data);
        if(!$scInsertResult) {
            echo "醒目留言解析异常";
            Log::error(date("Y-m-d H:i:s")."醒目留言解析异常");
            exit();
        }else {
            echo "醒目留言解析完成，下一步，解析大航海",PHP_EOL;
        }
    }

    /**
     * 插入大航海
     * @param array $fileInfo 文件来源信息
     * @param array $guardList 大航海列表
     */
    private function insertGuard(array &$fileInfo, array &$guardList) {
        echo "======= 大航海解析 =======",PHP_EOL;
        $data = [
            "fileInfo" => $fileInfo,
            "guardList" => $guardList
        ];
        $scInsertResult = $this->guardService->insertGuard($data);
        if(!$scInsertResult) {
            echo "大航海解析异常";
            Log::error(date("Y-m-d H:i:s")."大航海解析异常");
            exit();
        }else {
            echo "大航海解析完成，下一步，文件标为已读",PHP_EOL;
        }
    }

    /**
     * 将文件标为已读
     * @param array $fileInfo 文件来源信息
     * @return bool
     */
    public function readedXML(array $fileInfo): bool
    {
        $data = [
            "id"           => $fileInfo["id"],
            "file_read"    => 1,
            "update_time"  => date("Y-m-d H:i:s")
        ];
        return $this->readedXMLModel->save($data);
    }

    /**
     * 验证文件是否合格
     * @param array $fileInfo
     * @return bool|string
     */
    public function validateXML(array $fileInfo): bool|string
    {
        try {
            simplexml_load_file($fileInfo['file_path']);
            return true;
        }catch (\Exception $e) {
            Log::error(date("Y-m-d H:i:s").$fileInfo['file_path'] . "[格式不正确！] 详情:" . $e->getMessage());
            return $fileInfo['file_name'] . "[格式不正确！]";
        }
    }
}